#include "KeyRecommender.hpp"
#include "Dictionary.hpp"
#include "Debug.hpp"
#include "Configuration.hpp"
#include "CacheManager.hpp"

namespace se {

CandidateResult::CandidateResult(const std::string &word, int32_t frequency, int32_t distance)
:_word(word), _frequency(frequency), _distance(distance) { }

bool CandidateResult::operator>(const CandidateResult &rhs) const {
    if (this->_distance == rhs._distance) {
        if (this->_frequency == rhs._frequency) {
            return this->_word > rhs._word;
        }
        return this->_frequency > rhs._frequency;
    }
    return this->_distance > rhs._distance;
}

KeyRecommender::KeyRecommender(const std::string &inquiry) : _inquiry(inquiry) { }

std::shared_ptr<nlohmann::json> KeyRecommender::queryResult() {
    std::shared_ptr<nlohmann::json> resultJson = this->queryFromCache();
    if(!resultJson->empty()) {
        return resultJson;
    }

    this->queryFromDictionary();

    for (int32_t i = 0; i < CONFIGURATION("RecommenderWrodsCount", int32_t) && !this->_candidate.empty(); ++i) {
        resultJson->push_back(this->_candidate.top()._word);
        this->_candidate.pop();
    }
    DEBUG_PRINT("%s", resultJson->dump().c_str());
    Singleton<CacheManager>::getInstance().insertToCache(std::make_pair(_inquiry, *resultJson));
    return resultJson;
}


void KeyRecommender::queryFromDictionary() {
    std::shared_ptr<std::map<std::string, int32_t>> result = Dictionary::getInstance().query(this->_inquiry);
    for (auto &element : *(result)) {
        this->_candidate.emplace(element.first, element.second,
                                 Dictionary::getEditDistance(this->_inquiry, element.first));
    }
}

std::shared_ptr<nlohmann::json> KeyRecommender::queryFromCache() {
    return Singleton<CacheManager>::getInstance().find(this->_inquiry);
}

}  // namespace se
